自定义事件的实现方式
使用 ws 库时,所有消息都通过同一个 message 事件传递。如果需要区分不同类型的消息(比如聊天消息、系统通知、心跳检测),就需要在消息体中自行定义事件字段:
// 客户端发送自定义事件
ws.send(JSON.stringify({
event: 'myEvent',
data: {
message: 'hello',
timestamp: Date.now()
}
}))
javascript
// 服务端解析事件类型
ws.on('message', (message) => {
const parsed = JSON.parse(message)
switch (parsed.event) {
case 'myEvent':
console.log('收到自定义事件:', parsed.data)
break
case 'ping':
ws.send(JSON.stringify({ event: 'pong' }))
break
default:
console.log('未知事件:', parsed.event)
}
})
javascript
这就是 Socket.IO 使用起来更方便的原因——它已经帮你定义好了事件系统、命名空间和房间,不需要手动做 JSON 序列化和事件分发。但在需要精细控制的场景下,ws 的这种自由度反而是优势。
在 NestJS 中使用自定义事件
NestJS 的 @SubscribeMessage 装饰器本质上就是做了事件分发。每个 @SubscribeMessage('eventName') 对应一个独立的事件处理器:
@WebSocketGateway(3031)
export class EventGateway {
@SubscribeMessage('chat')
handleChat(@MessageBody() data: any, client: any): void {
console.log('chat message:', data)
// 广播给其他客户端...
}
@SubscribeMessage('notification')
handleNotification(@MessageBody() data: any): void {
console.log('notification:', data)
}
}
typescript
Network 面板中的 WebSocket 调试
在 Chrome DevTools 的 Network 面板中,筛选 WS 类型的请求,可以看到 WebSocket 连接的完整信息:
- Headers 标签:查看握手过程,
Connection: Upgrade表示这是一个协议升级请求 - Messages 标签:查看所有发送和接收的消息,包括时间和内容
握手请求中 Status Code: 101 Switching Protocols 确认协议升级成功,此后连接从 HTTP 切换为 WebSocket。
心跳检测的应用层实现
浏览器端的原生 WebSocket 对象不支持底层 ping/pong 帧(这是 ws 库在 Node.js 端的特权),因此需要在应用层自行实现:
// 客户端心跳逻辑
ws.onopen = function () {
// 连接成功后启动心跳
heartbeat()
}
function heartbeat() {
// 每 30 秒发送一次 ping
setInterval(() => {
ws.send(JSON.stringify({ event: 'ping' }))
}, 30000)
}
ws.onmessage = function (event) {
const data = JSON.parse(event.data)
if (data.event === 'pong') {
// 收到 pong 响应,连接正常
console.log('心跳检测: 连接正常')
} else {
// 处理其他业务消息
console.log('业务消息:', data)
}
}
javascript
// 服务端响应心跳
ws.on('message', (message) => {
const data = JSON.parse(message)
if (data.event === 'ping') {
ws.send(JSON.stringify({ event: 'pong' }))
}
})
javascript
心跳检测的完整流程
- 客户端连接成功后,启动定时器,每隔固定时间(如 30 秒)发送一次 ping
- 服务端收到 ping 后立即回复 pong
- 客户端收到 pong 后重置超时计时器
- 如果客户端在指定时间内(如 5 秒)没有收到 pong,认为连接异常,触发重连逻辑
- 服务端也可以设置超时——如果长时间没收到客户端的 ping,主动关闭连接释放资源
这个 ping/pong 循环构成了心跳检测的基础,后续章节会将它封装为完整的工具类。
↑